/*
 * RecursivePentamino.cpp
 *
 *  Created on: Jun 28, 2011
 *      Author: denis
 */


#include <iostream>
#include <vector>

#include <fstream>
#include "types.h"
#include "init_pent.h"
#include "constants.h"

using namespace std;

class Pentamino {
	int idepth;
	longvector* iprevious_steps_array;
	longvector current_pentamino_type;
	unsigned long long current_field_status;
	pentaminos_vector* ipentaminos_vector;
	ofstream* destfile;
public:
	Pentamino(longvector* previous_steps_array,	pentaminos_vector* pentaminos_array, int depth, ofstream* in_destfile) {
		idepth = depth;
		current_pentamino_type = *((*pentaminos_array)[depth]);
		destfile=in_destfile;
		longvector::iterator itt;

		iprevious_steps_array= new longvector;
		for(itt=previous_steps_array->begin();itt!=previous_steps_array->end();itt++){
			iprevious_steps_array->push_back(*itt);

		}

		//iprevious_steps_array = *previous_steps_array;


		ipentaminos_vector = pentaminos_array;

		longvector::iterator it;

		current_field_status=0;

		for (it = iprevious_steps_array->begin(); it!= iprevious_steps_array->end(); it++) // making map of all currently laid pentaminos
		{
			current_field_status = current_field_status ^ (*it);
		}
	}

	bool CheckRegions(unsigned long long m_field){
		unsigned long long field =~m_field & ALLOWED_BITS;

		unsigned long long ft=field;

		unsigned long long area,area_prev,cp_area;

		unsigned long long first_one=0;


		int region_size=0;

		bool flag=true;

		while ((field != 0)and flag){
			ft=field;
			ft= ft& (ft-1);

			first_one=(field) ^ ft;
			area=first_one;
			area_prev=area+1;
			while (area_prev!=area)	{
				area_prev=area;
				area=area|((area>>1) & LEFT_NULL_COLUMN );
				area=area|((area<<1) & RIGHT_NULL_COLUMN);
				area=area|((area>>10)&TOP_NULL_ROW);
				area=area|((area<<10) & BOTTOM_NULL_ROW);
				area = field & area;
			}
			cp_area=area;
			field=field -area;
			region_size=0;
			while (cp_area !=0){
				cp_area=cp_area&(cp_area-1);
				region_size++;

			}
			flag= (region_size % 5) ==0;
		}
	return flag;
	}
	void goToNextLevel() {

		Pentamino* NextLevel = 0;

		unsigned long long current_position = 0;
		unsigned long long bit_intersection = 0;
		unsigned long long bit_union = 0;
		unsigned long long default_current_position =0;
		unsigned long long temp_position=0;
		longvector::iterator rotation;
		longvector::iterator element;
		int xsubs=0;
		int ysubs=0;
		for (rotation = current_pentamino_type.begin(); rotation!= current_pentamino_type.end(); rotation++) {
			default_current_position=*rotation;
			temp_position=default_current_position;
			ysubs=0;
			while(((~TOP_NULL_ROW)&temp_position)!=0){
				temp_position=temp_position<<X_MAX;
				ysubs++;

			}
			xsubs=0;
			temp_position=default_current_position;
			while(((~LEFT_NULL_COLUMN)&temp_position)!=0){
				temp_position=(temp_position<<1) & RIGHT_NULL_COLUMN;
				xsubs++;

			}
			ysubs--;//because we must count initial position too
			xsubs--;
			for (int ycount = Y_MIN; ycount < Y_MAX-ysubs; ycount++) {
				current_position = (default_current_position >> ((X_MAX)* ycount));
				for (int xcount = X_MIN; xcount < X_MAX-xsubs; xcount++) {


					bit_intersection=current_position & current_field_status;

					bit_union=current_position ^ current_field_status;

					if ((bit_intersection== 0)&&(CheckRegions(current_position ^ current_field_status))) {
						iprevious_steps_array->push_back(current_position);
						if (idepth == 11) {

							for (element = iprevious_steps_array->begin(); element!= iprevious_steps_array->end(); element++) {
								*destfile<< *element << ' ';
								std::cout<< *element << ' ';
							}
							current_field_status=0;
							for (element = iprevious_steps_array->begin(); element!= iprevious_steps_array->end(); element++) {
										current_field_status=current_field_status ^ *element;
									}
							iprevious_steps_array->clear();
							*destfile<<"\n";
							std::cout << "\n";
						} else {
							//iprevious_steps_array.push_back(current_position);
							NextLevel = new Pentamino(iprevious_steps_array,ipentaminos_vector, idepth + 1,destfile);
							NextLevel->goToNextLevel();
							iprevious_steps_array->pop_back();
							delete(NextLevel);
						}
					}
					current_position = (current_position >> 1)& LEFT_NULL_COLUMN;
				}

			}
		}
	iprevious_steps_array->clear();
	delete(iprevious_steps_array);
	}
	;
};


int objectoriented(){

	pentaminos_vector* rotations=Initialization();

	std::ofstream dedstfile("/home/denis/pentamino_solutions_2339.txt");

	//ofstream* destfile;
	longvector* steps_array= new longvector;
	longvector* first_element=(*rotations)[0];
	unsigned long long g_current_position = 0;
	unsigned long long g_bit_intersection = 0;
	//int temp;
	unsigned long long g_default_current_position =0;
	Pentamino* FirstIter;
	g_default_current_position=(*first_element)[0];
	for (int ycount = Y_MIN; ycount < 2; ycount++) {
		g_current_position = (g_default_current_position >> ((X_MAX)* ycount));

		for (int xcount = X_MIN; xcount < 4; xcount++) {
			steps_array->push_back(g_current_position);
						FirstIter = new Pentamino(steps_array,rotations, 1,&dedstfile);
			FirstIter->goToNextLevel();
			steps_array->pop_back();
			delete(FirstIter);
			g_current_position = (g_current_position >> 1)& LEFT_NULL_COLUMN;
		}
	}

	//free(FirstIter);
	pentaminos_vector::iterator penvecit;
	for(penvecit=rotations->begin();penvecit!=rotations->end();penvecit++){
		(*penvecit)->clear();
	}
	rotations->clear();

return 0;
}

